package com.demo.base.http;

import cn.hutool.http.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author 曳戈泰尔
 * @version 1.0
 * @description HTTP请求单元类
 * @date 2023/3/13 2:09 PM
 */
@Slf4j
public class HttpClientHelper {

    /** 请求配置 */
    private static RequestConfig requestConfig = null;

    private HttpClientHelper() {
        // 设置http的状态参数
        requestConfig =
                RequestConfig.custom()
                        .setSocketTimeout(5000)
                        .setConnectTimeout(5000)
                        .setConnectionRequestTimeout(5000)
                        .build();
        // TODO 补充其他配置
    }

    /**
     * 有参数的GET请求
     *
     * <p>Params参数
     *
     * @param url
     * @param param map参数
     * @return
     */
    public static String doGet(String url, Map<String, String> param) {

        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();

        String resultString = null;
        CloseableHttpResponse response = null;

        try {
            // 创建uri
            URIBuilder builder = new URIBuilder(url);
            if (param != null) {
                for (String key : param.keySet()) {
                    builder.addParameter(key, param.get(key));
                }
            }
            URI uri = builder.build();

            // 创建http GET请求
            HttpGet httpGet = new HttpGet(uri);
            httpGet.setConfig(requestConfig);

            // 执行请求
            response = httpClient.execute(httpGet);

            // 判断返回状态是否为200
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                resultString = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
            }
        } catch (Exception e) {
            log.error("HttpClient GET请求发生异常，原因：{}", e.getMessage());
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                if (httpClient != null) {
                    httpClient.close();
                }
            } catch (IOException e) {
                log.error("HttpClient GET请求关闭流失败，原因：{}", e.getMessage());
            }
        }

        return resultString;
    }

    /**
     * 有参数的GET请求
     *
     * <p>Params参数
     *
     * <p>带请求Header
     *
     * @param url
     * @param param map参数
     * @return
     */
    public static String doGet(String url, Map<String, String> param, String keyHeader) {

        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();

        String resultString = null;
        CloseableHttpResponse response = null;

        try {
            // 创建uri
            URIBuilder builder = new URIBuilder(url);
            if (param != null) {
                for (String key : param.keySet()) {
                    builder.addParameter(key, param.get(key));
                }
            }
            URI uri = builder.build();

            // 创建http GET请求
            HttpGet httpGet = new HttpGet(uri);
            httpGet.setConfig(requestConfig);

            // 设置请求头
            httpGet.setHeader("x-api-key", keyHeader);

            // 执行请求
            response = httpClient.execute(httpGet);

            // 判断返回状态是否为200
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                resultString = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
            }
        } catch (Exception e) {
            log.error("HttpClient GET请求发生异常，原因：{}", e.getMessage());
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                if (httpClient != null) {
                    httpClient.close();
                }
            } catch (IOException e) {
                log.error("HttpClient GET请求关闭流失败，原因：{}", e.getMessage());
            }
        }

        return resultString;
    }

    /**
     * 带Header的请求
     *
     * <p>JSON参数
     *
     * @param url
     * @param json
     * @param keyHeader
     * @return
     */
    public static String doGet(String url, String json, String keyHeader) {

        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();

        String resultString = null;
        CloseableHttpResponse response = null;

        try {
            // 创建http GET请求
            HttpGetWithEntity httpGetWithEntity = new HttpGetWithEntity(url);
            httpGetWithEntity.setConfig(requestConfig);

            // 设置Header
            httpGetWithEntity.setHeader("x-api-key", keyHeader);

            // 设置请求参数
            HttpEntity httpEntity = new StringEntity(json, ContentType.APPLICATION_JSON);
            httpGetWithEntity.setEntity(httpEntity);

            // 执行请求
            response = httpClient.execute(httpGetWithEntity);

            // 判断返回状态是否为200
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                resultString = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
            }
        } catch (Exception e) {
            log.error("HttpClient GET请求发生异常，原因：{}", e.getMessage());
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                if (httpClient != null) {
                    httpClient.close();
                }
            } catch (IOException e) {
                log.error("HttpClient GET请求关闭流失败，原因：{}", e.getMessage());
            }
        }

        return resultString;
    }

    /**
     * 无参数的GET请求
     *
     * @param url
     * @return
     */
    public static String doGet(String url) {
        return doGet(url, null);
    }

    /**
     * 有参数的POST请求
     *
     * <p>form-data参数
     *
     * @param url
     * @param param Map参数
     * @return
     */
    public static String doPost(String url, Map<String, Object> param) {

        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();

        CloseableHttpResponse response = null;
        String resultString = null;

        try {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);
            httpPost.setConfig(requestConfig);

            // 创建参数列表
            if (param != null) {
                List<NameValuePair> paramList = new ArrayList<>();
                for (String key : param.keySet()) {
                    paramList.add(new BasicNameValuePair(key, (String) param.get(key)));
                }

                // 模拟表单
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
                httpPost.setEntity(entity);
            }

            // 执行http请求
            response = httpClient.execute(httpPost);

            // 判断返回状态是否为200
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                resultString = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
            }

        } catch (Exception e) {
            log.error("HttpClient POST请求发生异常，原因：{}", e.getMessage());
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                if (httpClient != null) {
                    httpClient.close();
                }
            } catch (IOException e) {
                log.error("HttpClient POST请求关闭流失败，原因：{}", e.getMessage());
            }
        }

        return resultString;
    }

    /**
     * 无参数的POST请求
     *
     * @param url
     * @return
     */
    public static String doPost(String url) {
        return doPost(url, null);
    }

    /**
     * 有参数的POST请求
     *
     * <p>Json参数
     *
     * @param url
     * @param json
     * @return
     */
    public static String doPostJson(String url, String json) {

        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();

        CloseableHttpResponse response = null;
        String resultString = null;

        try {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);
            httpPost.setConfig(requestConfig);

            // 创建请求内容
            httpPost.setHeader("Connection", "Keep-Alive");
            httpPost.setHeader("Content-Type", "application/json;charset=utf-8");

            StringEntity entity = new StringEntity(json);
            entity.setContentType("application/json;charset=utf-8");
            httpPost.setEntity(entity);

            // 执行http请求
            response = httpClient.execute(httpPost);

            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                resultString = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
            }
        } catch (Exception e) {
            log.error("HttpClient POST请求发生异常，原因：{}", e.getMessage());
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                if (httpClient != null) {
                    httpClient.close();
                }
            } catch (IOException e) {
                log.error("HttpClient POST请求关闭流失败，原因：{}", e.getMessage());
            }
        }

        return resultString;
    }

    /**
     * 有参数的POST请求
     *
     * <p>Json参数
     *
     * <p>字节支付专用接口，因为字节支付请求与其他API不兼容
     *
     * <p>HuTool实现
     *
     * @param url
     * @param json
     * @return
     */
    public static String doPayPostJson(String url, String json) {

        return HttpUtil.post(url, json, 3000);
    }

    /**
     * 有参数的POST请求
     *
     * <p>JOSN参数
     *
     * <p>增加请求Header
     *
     * @param url
     * @param json
     * @param keyHeader
     * @return
     * @throws Exception
     */
    public static String doPostJson(String url, String json, String keyHeader) {

        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();

        CloseableHttpResponse response = null;
        String resultString = null;

        try {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);
            httpPost.setConfig(requestConfig);

            // 创建请求内容
            httpPost.setHeader("Connection", "Keep-Alive");
            httpPost.setHeader("Content-Type", "application/json;charset=utf-8");

            // 设置鉴权请求头
            httpPost.setHeader("Authorization", keyHeader);

            // 创建请求内容
            StringEntity entity = new StringEntity(json);
            entity.setContentType("application/json;charset=utf-8");
            httpPost.setEntity(entity);

            // 执行http请求
            response = httpClient.execute(httpPost);

            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                resultString = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
            }
        } catch (Exception e) {
            log.error("HttpClient POST请求发生异常，原因：{}", e.getMessage());
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                if (httpClient != null) {
                    httpClient.close();
                }
            } catch (IOException e) {
                log.error("HttpClient POST请求关闭流失败，原因：{}", e.getMessage());
            }
        }

        return resultString;
    }
}
